import React, { Component } from "react";
import ReactDOM from "react-dom";
import PropTypes from 'prop-types';

import {
    FLOW_CONTROL_1,
    FLOW_CONTROL_2,
    FLOW_CONTROL_3,
    FLOW_CONTROL_4,
    FLOW_CONTROL_5,
    FLOW_CONTROL_6,
    FLOW_CONTROL_7,
    FLOW_CONTROL_8,
    FLOW_CONTROL_9,
    FLOW_CONTROL_10
} from "./AppConst";


/**
 * React Props
 * 
 * state 和 props 主要的区别在于 props 是不可变的，而 state 可以根据与用户交互来改变。
 * 这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
 * 
 * @date: 2020-11-22
 */


function HelloMessage(props) {
    return <h1>Hello {props.name}!</h1>
}

function SampleHelloMsg() {
    return <HelloMessage name="Runoob" />
}


class HelloMsg extends React.Component {
    render() {
        return (<h1>Hello,默认属性为: {this.props.name}</h1>);
    }
}

/**
 * 默认属性控件 
 *
 */
function SampleDefPropsComponent() {
    // 为组件配置默认属性
    HelloMsg.defaultProps = {
        name: 'Runoob'
    }
    return <HelloMsg />
}


/** ----------------------------  Sate和Props的组合使用 ---------------------------- */
class Name extends React.Component {
    render() {
        console.log("render Name ... ");
        return (
            <h1>
                {this.props.name}
            </h1>
        );
    }
}

class Link extends React.Component {
    render() {
        console.log("render Link ... ");
        return (
            // 组合使用props和site
            <a href={this.props.site}>
                {this.props.site}
            </a>
        );
    }
}


/**
 * 组合控件
 */
class Website extends React.Component {
    constructor() {
        super();

        this.state = {
            name: '菜鸟教程',
            site: 'http://www.runoob.com'
        }
    }
    render() {
        console.log("render Website ... ");
        return (
            <div>
                <Name name={this.state.name} />
                <Link site={this.state.site} />
            </div>);
    }
}


function SampleComposeStateAndProps() {
    return <Website />
}

/** ----------------------------  Sate和Props的组合使用 ---------------------------- */
var title = "菜鸟教程";

class MyTitle extends React.Component {
    render() {
        return <h1>Hello,{this.props.title}</h1>
    }
}



/**  
 * PropTypes 需要使用
 *  npm install prop-types
 * 安装
 */

/**
 * 校验title
 */
function verificationTitle() {
    MyTitle.prototype = {
        title: PropTypes.string
    }
    return <MyTitle title={title} />
}


class MyComponent extends Component {
    render() {
        return <h1>Hello,自定义组件,{this.props.title}</h1>
    }
}

/**
 * 自定义验证器
 */

function sampleMyPtComponent() {
    MyComponent.PropTypes = {
        //  可以声明prop为指定的JS基本数据类型，默认情况，这些数据是可选的
        optionalArray: React.PropTypes.array,
        optionalBool: React.PropTypes.bool,
        optionalFunc: React.PropTypes.func,
        optionalNumber: React.PropTypes.number,
        optionalObject: React.PropTypes.object,
        optionalString: React.PropTypes.string,

        // 可以被渲染的对象numbers,strings,elements,或array
        optionalNode: React.PropTypes.node,

        // React元素
        optionalNode: React.PropTypes.element,

        // 用JS的instanceof 操作符声明prop为类的实例
        optionalMessage: React.PropTypes.instanceOf(Message),

        // 用enum来限制prop只接受指定的值
        optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

        // 可以是多个对象类型中的一个
        optionalUnion: React.PropTypes.oneOfType([
            React.PropTypes.string,
            React.PropTypes.number,
            React.PropTypes.instanceOf(Message)
        ]),


        // 指定类型组成的数组
        optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),


        // 指定类型的属性构成的对象
        optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),


        // 指定shape参数的对象
        optionalObjectWithShape: React.PropTypes.shape(
            {
                color: React.PropTypes.string,
                fontSize: React.PropTypes.number
            }
        ),


        // 任意类型加上 'isRequired'来使prop不可空
        requiredFunc: React.PropTypes.func.isRequired,


        // 不可为空的任意类型
        requiredFunc: React.PropTypes.any.isRequired,

        // 自定义验证器。 如果验证失败需要返回一个Error对象。不要直接使用'console.warn'或抛出异常
        // ,因为这样'oneOfType'会失效
        customProp: function (props, propName, componentName) {
            if (!/matchme/.test(props[propName])) {
                return new Error('Validation failed!');
            }
        }

    }
}


function buildComponentUi(flag) {
    console.log("buildComponentUi flag = " + flag);
    switch (flag) {
        case FLOW_CONTROL_1:
            return SampleHelloMsg();
        case FLOW_CONTROL_2:
            return SampleDefPropsComponent();
        case FLOW_CONTROL_3:
            return SampleComposeStateAndProps();
        case FLOW_CONTROL_4:
            return verificationTitle();
    }
}



/**
 * 执行渲染
 * @param {标记位} flag 
 */
function execRender(flag) {
    console.log("execRender flag = " + flag);
    ReactDOM.render(
        buildComponentUi(flag),
        document.getElementById('container')
    );
}


function propsMain() {
    execRender(FLOW_CONTROL_4);
}


export { propsMain }